/**
 * 文件下载
 * @param {String} url 
 * @param {Object} options 
 * @param {Object} options.id 下载目录ID，默认fileDownload
 * @param {Object} options.fileSize 下载文件阀值，默认50M，文件超过次大小则使用fileApi下载
 * @param {Object} options.fetch
 * @param {Object} options.onProgress 下载进度回调
 */
export default async function fileDownload(url, options) {
  let ops = {
    id: 'fileDownload',
    onProgress(){},
    // 50M
    fileSize: 50 * 1024 * 1024,
  };
  Object.assign(ops, options);


  const controller = new AbortController();

  const response = await fetch(url, {
    signal: controller.signal,
    ...ops.fetch,
  });

  response.controller = controller;

  if (!response.ok) {
    throw new Error(`网络响应失败，状态码: ${response.status}`);
  }



  const contentLength = response.headers.get('content-length');
  let total = contentLength ? parseInt(contentLength, 10) : null;

  if (total < ops.fileSize) {
    return generalDownload(response, total, ops);
  } else {
    return fileApiDownload(response, total, ops);
  }
}

async function generalDownload(response, total, ops){
  const filename = getFileNameFromResponse(response, ops);

  let loaded = 0;
  let reader = response.body.getReader();
  let chunks = [];

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    chunks.push(value);
    loaded += value.length;

    if (total !== null) {
      const percentComplete = (loaded / total) * 100;
      ops.onProgress(percentComplete, total, loaded);
    }
  }

  let contentType = response.headers.get('content-type');
  let blob = new Blob(chunks, { type: contentType });

  let a = document.createElement('a');
  let url = URL.createObjectURL(blob);
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url);
  reader.cancel();
  url = null;
  reader = null;
  chunks = [];
  blob = null;
  a.href = '';
  a = null;
}

async function fileApiDownload(response, total, ops){
  if (!(window.showSaveFilePicker instanceof Function)) {
    console.warn('当前浏览器不支持 File System API');
    return generalDownload(response, total, ops);
  }
  let filename = getFileNameFromResponse(response, ops);
  let fileHandle = await window.showSaveFilePicker({ startIn: 'downloads', suggestedName: filename });
  let fileWriter = await fileHandle.createWritable();

  // 创建 TransformStream 来监听进度
  const progressStream = new TransformStream({
    loaded: 0,
    total,
    transform(chunk, controller) {
      this.loaded += chunk.length;
      if (total !== null) {
        const percentComplete = (this.loaded / this.total) * 100;
        ops.onProgress(percentComplete, this.total, this.loaded);
      }
      controller.enqueue(chunk);
    }
  });

  return response.body.pipeThrough(progressStream).pipeTo(fileWriter);
}

function getFileNameFromResponse(response, options){
  if (options.filename){
    return options.filename;
  }
  let filename = response.headers.filename;
  if (!filename && response.headers['content-disposition']) {
    let h = response.headers['content-disposition'];
    filename = h.substr(h.indexOf('filename=') + 9);
  }
  if (filename){
    return decodeURI(filename);
  } else {
    let path = new URL(response.url).pathname;
    return path.substring(path.lastIndexOf('/') + 1);
  }
}